#include "GameState.h"

#include <cstdlib>			//used for random
#include <ctime>			//used for time from random
#include <iostream>

namespace catan
{

GameState::GameState(): _isRunning(true), isFrameDrawn(false), isMaskDrawn(true), areHexagonsDrawn(true), isBackgroundDrawn(true), isPreStartGame(true), isPlacingSettlement(true), screenNumber(0), currentPlayerIndex(0), isRollDiceButtonEnabled(true), isBuyRoadButtonEnabled(false), isBuyRoadButtonPressed(false), isBuySettlementButtonEnabled(false), isBuySettlementButtonPressed(false), isCityUpgradeButtonEnabled(false), isCityUpgradeButtonPressed(false), isBuyDevelopmentCardButtonEnabled(false), isPlayerTradeButtonEnabled(false), isPlayerTradeButtonPressed(false), isBankTradeButtonEnabled(false), isBankTradeButtonPressed(false), isEndTurnButtonEnabled(false)
{
	keyDownEventRef = NULL;
	mouseButtonDownEventRef = NULL;
	mouseMotionEventRef = NULL;
	srand((int)time(0));	//set the seed for random generation;
	rollDice();
	for(int i=0; i<DevelopmentCard::getVectorOfShuffledEnumValues().size(); i++){
		developmentDeck.push_back(DevelopmentCard(DevelopmentCard::getVectorOfShuffledEnumValues().at(i)));
	}
}

GameState::~GameState()
{
}

void GameState::end()
{
	_isRunning = false;
}

bool GameState::isRunning()
{
	return _isRunning;
}

void GameState::rollDice()
{
	dice.clear();
	dice.push_back(rand()%6+1);
	dice.push_back(rand()%6+1);
	dice.push_back(rand()%4);
	dice.push_back(rand()%4);
}

std::vector<int> GameState::getRolledDice()
{
	return dice;
}

bool GameState::getIsFrameDrawn()
{
	return isFrameDrawn;
}

void GameState::toggleFrame()
{
	isFrameDrawn = !isFrameDrawn;
}

bool GameState::getIsMaskDrawn()
{
	return isMaskDrawn;
}

void GameState::toggleMask()
{
	isMaskDrawn = !isMaskDrawn;
}

bool GameState::getAreHexagonsDrawn()
{
	return areHexagonsDrawn;
}

void GameState::toggleHexagons()
{
	areHexagonsDrawn = !areHexagonsDrawn;
}

bool GameState::getIsBackgroundDrawn()
{
	return isBackgroundDrawn;
}

void GameState::toggleBackground()
{
	isBackgroundDrawn = !isBackgroundDrawn;
}

SDL_Event *GameState::pollKeyDownEvent()
{
	SDL_Event *retval = keyDownEventRef;
	keyDownEventRef = NULL;
	return retval;
}

void GameState::setIsPlacingSettlement(bool isPlacingSettlement)
{
	this->isPlacingSettlement = isPlacingSettlement;
}

bool GameState::getIsPlacingSettlement()
{
	return isPlacingSettlement;
}

void GameState::nextScreen()
{
	setScreenNumber(getScreenNumber()+1);
}

void GameState::setScreenNumber(int screenNumber)
{
	this->screenNumber = screenNumber;
}

int GameState::getScreenNumber()
{
	return screenNumber;
}

void GameState::nextPlayer()
{
	currentPlayerIndex = (currentPlayerIndex + 1) % numberOfPlayers;
}

int GameState::getPlayerIndex()
{
	return currentPlayerIndex;
}

void GameState::setNumberOfPlayers(int numberOfPlayers)
{
	this->numberOfPlayers = numberOfPlayers;
}

int GameState::getNumberOfPlayers()
{
	return numberOfPlayers;
}

void GameState::addPlayer(Player player)
{
	players.push_back(player);
}

std::vector<Player*> GameState::getPlayers()
{
	std::vector<Player*> playerReferences;
	for (std::vector<Player>::iterator playerIterator = players.begin(); playerIterator != players.end(); ++playerIterator)
	{
		playerReferences.push_back(&*playerIterator);
	}
	return playerReferences;
}

void GameState::setIsPreStartGame(bool isPreStartGame)
{
	this->isPreStartGame = isPreStartGame;
}

bool GameState::getIsPreStartGame()
{
	return isPreStartGame;
}

bool GameState::getIsRollDiceButtonEnabled()
{
	return isRollDiceButtonEnabled;
}

void GameState::setIsRollDiceButtonEnabled(bool isRollDiceButtonEnabled)
{
	this->isRollDiceButtonEnabled = isRollDiceButtonEnabled;
}

bool GameState::getIsBuyRoadButtonEnabled()
{
	return isBuyRoadButtonEnabled;
}

void GameState::setIsBuyRoadButtonEnabled(bool isBuyRoadButtonEnabled)
{
	this->isBuyRoadButtonEnabled = isBuyRoadButtonEnabled && canAddRoad(players.at(currentPlayerIndex));
}

bool GameState::getIsBuyRoadButtonPressed()
{
	return isBuyRoadButtonPressed;
}

void GameState::setIsBuyRoadButtonPressed(bool isBuyRoadButtonPressed)
{
	this->isBuyRoadButtonPressed = isBuyRoadButtonPressed;
}

bool GameState::getIsBuySettlementButtonEnabled()
{
	return isBuySettlementButtonEnabled;
}

void GameState::setIsBuySettlementButtonEnabled(bool isBuySettlementButtonEnabled)
{
	this->isBuySettlementButtonEnabled = isBuySettlementButtonEnabled && canAddSettlement(players.at(currentPlayerIndex));
}

bool GameState::getIsBuySettlementButtonPressed()
{
	return isBuySettlementButtonPressed;
}

void GameState::setIsBuySettlementButtonPressed(bool isBuySettlementButtonPressed)
{
	this->isBuySettlementButtonPressed = isBuySettlementButtonPressed;
}

bool GameState::getIsCityUpgradeButtonEnabled()
{
	return isCityUpgradeButtonEnabled;
}

void GameState::setIsCityUpgradeButtonEnabled(bool isCityUpgradeButtonEnabled)
{
	this->isCityUpgradeButtonEnabled = isCityUpgradeButtonEnabled && canCityUpgrade(players.at(currentPlayerIndex));
}

bool GameState::getIsCityUpgradeButtonPressed()
{
	return isCityUpgradeButtonPressed;
}

void GameState::setIsCityUpgradeButtonPressed(bool isCityUpgradeButtonPressed)
{
	this->isCityUpgradeButtonPressed = isCityUpgradeButtonPressed;
}

bool GameState::getIsBuyDevelopmentCardButtonEnabled()
{
	return isBuyDevelopmentCardButtonEnabled;
}

void GameState::setIsBuyDevelopmentCardButtonEnabled(bool isBuyDevelopmentCardButtonEnabled)
{
	this->isBuyDevelopmentCardButtonEnabled = isBuyDevelopmentCardButtonEnabled && developmentDeck.size() > 0 && players.at(currentPlayerIndex).getResources().containsAtLeast(catan::developmentCost);
}

bool GameState::getIsPlayerTradeButtonEnabled()
{
	return isPlayerTradeButtonEnabled;
}

void GameState::setIsPlayerTradeButtonEnabled(bool isPlayerTradeButtonEnabled)
{
	this->isPlayerTradeButtonEnabled = isPlayerTradeButtonEnabled && !(players.at(currentPlayerIndex).getResources() == catan::resourceEmpty);
}

bool GameState::getIsPlayerTradeButtonPressed()
{
	return isPlayerTradeButtonPressed;
}

void GameState::setIsPlayerTradeButtonPressed(bool isPlayerTradeButtonPressed)
{
	this->isPlayerTradeButtonPressed = isPlayerTradeButtonPressed;
}

bool GameState::getIsBankTradeButtonEnabled()
{
	return isBankTradeButtonEnabled;
}

void GameState::setIsBankTradeButtonEnabled(bool isBankTradeButtonEnabled)
{
	this->isBankTradeButtonEnabled = isBankTradeButtonEnabled && !(players.at(currentPlayerIndex).getResources() == catan::resourceEmpty);
}

bool GameState::getIsBankTradeButtonPressed()
{
	return isBankTradeButtonPressed;
}

void GameState::setIsBankTradeButtonPressed(bool isBankTradeButtonPressed)
{
	this->isBankTradeButtonPressed = isBankTradeButtonPressed;
}

bool GameState::getIsEndTurnButtonEnabled()
{
	return isEndTurnButtonEnabled;
}

void GameState::setIsEndTurnButtonEnabled(bool isEndTurnButtonEnabled)
{
	this->isEndTurnButtonEnabled = isEndTurnButtonEnabled;
}

void GameState::queueKeyDownEvent(SDL_Event &event)
{
	keyDownEventRef = &event;
}

SDL_Event *GameState::pollMouseButtonDownEvent()
{
	SDL_Event *retval = mouseButtonDownEventRef;
	mouseButtonDownEventRef = NULL;
	return retval;
}

void GameState::queueMouseButtonDownEvent(SDL_Event &event)
{
	mouseButtonDownEventRef = &event;
}

SDL_Event *GameState::pollMouseMotionEvent()
{
	SDL_Event *retval = mouseMotionEventRef;
	mouseMotionEventRef = NULL;
	return retval;
}

void GameState::queueMouseMotionEvent(SDL_Event &event)
{
	mouseMotionEventRef = &event;
}

bool GameState::isTheEnd(){
	return(players.at(currentPlayerIndex).getVictoryPoints(false, false) >= catan::MAXGAMEPOINTS);
}

std::vector<DevelopmentCard> &GameState::getDevelopmentDeck(){
	return developmentDeck;
}

bool GameState::canAddRoad(Player &player)
{
	return player.getNmbOfRoadsLeft() > 0 && (player.getNmbOfSettlementsPlaced()+player.getNmbOfCitiesPlaced()) > 0 && (player.getNmbOfRoadsPlaced() < 2 || player.getResources().containsAtLeast(catan::roadCost));
}

bool GameState::canAddRoad(Player &player, GameMap &gameMap, PathCoordinate road)
{
	std::vector<PathCoordinate> roads;
	for (std::vector<Player>::iterator playerIterator = players.begin(); playerIterator != players.end(); ++playerIterator)
	{
		roads = playerIterator->getRoads();
		for (std::vector<PathCoordinate>::iterator roadIterator = roads.begin(); roadIterator != roads.end(); ++roadIterator)
		{
			if (road == *roadIterator)
			{
				return false;
			}
		}
	}
	roads = player.getRoads();
	for (std::vector<PathCoordinate>::iterator roadIterator = roads.begin(); roadIterator != roads.end(); ++roadIterator)
	{
		std::map<HorizontalCardinal, Path*> pathsNeighboringPath = gameMap.getPathsNeighboringPath(gameMap.getPath(*roadIterator));
		for (std::map<HorizontalCardinal, Path*>::iterator pathIterator = pathsNeighboringPath.begin(); pathIterator != pathsNeighboringPath.end(); ++pathIterator)
		{
			if (pathIterator->second->getCoordinate() == road)
			{
				return canAddRoad(player);
			}
		}
	}
	std::map<HorizontalCardinal, Site*> sitesNeighboringPath = gameMap.getSitesNeighboringPath(gameMap.getPath(road));
	for (std::map<HorizontalCardinal, Site*>::iterator neighborIterator = sitesNeighboringPath.begin(); neighborIterator != sitesNeighboringPath.end(); ++neighborIterator)
	{
		SiteCoordinate siteCoordinateCandidate = neighborIterator->second->getCoordinate(); 
		std::vector<SiteCoordinate> settlements = player.getSettlements();
		for (std::vector<SiteCoordinate>::iterator settlementIterator = settlements.begin(); settlementIterator != settlements.end(); ++settlementIterator)
		{
			if (*settlementIterator == siteCoordinateCandidate)
			{
				return canAddRoad(player);
			}
		}
		std::vector<SiteCoordinate> cities = player.getCities();
		for (std::vector<SiteCoordinate>::iterator cityIterator = cities.begin(); cityIterator != cities.end(); ++cityIterator)
		{
			if (*cityIterator == siteCoordinateCandidate)
			{
				return canAddRoad(player);
			}
		}
	}
	return false;
}

bool GameState::canAddSettlement(Player &player)
{
	return player.getNmbOfSettlementsLeft() > 0 && (player.getNmbOfSettlementsPlaced() < 2 || player.getResources().containsAtLeast(catan::settlementCost));
}

bool GameState::canAddSettlement(Player &player, GameMap &gameMap, SiteCoordinate settlement)
{
	for (std::vector<Player>::iterator playerIterator = players.begin(); playerIterator != players.end(); ++playerIterator)
	{
		std::vector<SiteCoordinate> settlements = playerIterator->getSettlements();
		for (std::vector<SiteCoordinate>::iterator settlementIterator = settlements.begin(); settlementIterator != settlements.end(); ++settlementIterator)
		{
			if (settlement == *settlementIterator)
			{
				return false;
			}
			std::map<HorizontalCardinal, Site*> neighboringSites = gameMap.getSitesNeighboringSite(gameMap.getSite(*settlementIterator));
			for (std::map<HorizontalCardinal, Site*>::iterator neighborIterator = neighboringSites.begin(); neighborIterator != neighboringSites.end(); ++neighborIterator)
			{
				if (settlement == neighborIterator->second->getCoordinate())
				{
					return false;
				}
			}
		}
		std::vector<SiteCoordinate> cities = playerIterator->getCities();
		for (std::vector<SiteCoordinate>::iterator cityIterator = cities.begin(); cityIterator != cities.end(); ++cityIterator)
		{
			if (settlement == *cityIterator)
			{
				return false;
			}
			std::map<HorizontalCardinal, Site*> neighboringSites = gameMap.getSitesNeighboringSite(gameMap.getSite(*cityIterator));
			for (std::map<HorizontalCardinal, Site*>::iterator neighborIterator = neighboringSites.begin(); neighborIterator != neighboringSites.end(); ++neighborIterator)
			{
				if (settlement == neighborIterator->second->getCoordinate())
				{
					return false;
				}
			}
		}
	}
	return canAddSettlement(player);
}

bool GameState::canCityUpgrade(Player &player)
{
	return player.getNmbOfCitiesLeft() > 0 && player.getNmbOfSettlementsPlaced() > 0 && player.getResources().containsAtLeast(catan::cityCost);
}

bool GameState::canCityUpgrade(Player &player, GameMap &gameMap, SiteCoordinate city)
{
	std::vector<SiteCoordinate> settlements = player.getSettlements();
	for (std::vector<SiteCoordinate>::const_iterator siteCoordinateIterator = settlements.begin(); siteCoordinateIterator != settlements.end(); ++siteCoordinateIterator)
	{
		if (city == *siteCoordinateIterator)
		{
			return canCityUpgrade(player);
		}
	}
	return false;
}

}
